package com.sky.business.sys.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.sky.business.sys.domain.CameraConfig;
import com.sky.business.sys.domain.Container;
import com.sky.business.sys.domain.Group;
import com.sky.business.sys.domain.SystemConfig;
import com.sky.business.sys.dto.CameraRtspInfo;
import com.sky.business.sys.dto.ControlModeDto;
import com.sky.business.sys.dto.OnvifDeviceInfo;
import com.sky.business.sys.param.CameraConfigListParam;
import com.sky.business.sys.param.CameraConfigParam;
import com.sky.business.sys.param.OnvifParam;
import com.sky.business.sys.param.PubStreamParam;
import com.sky.business.sys.service.*;
import com.sky.business.sys.vo.CameraConfigVO2;
import com.sky.business.sys.vo.CameraConfigVo;
import com.sky.common.api.Result;
import com.sky.common.config.CacheConstants;
import com.sky.common.enums.ControlMode;
import com.sky.common.enums.TaskType;
import com.sky.common.utils.GeneratorUtil;
import com.sky.common.utils.NumberUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.xml.soap.SOAPException;
import java.net.ConnectException;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@RestController
@Tag(name = "设备配置管理", description = "设备配置控制层")
@RequestMapping("/cameraConfig")
@Validated
public class CameraConfigController {

    @Autowired
    private CameraConfigService cameraConfigService;

    @Autowired
    private SystemConfigService systemConfigService;

    @Autowired
    private OnvifService onvifService;

    @Autowired
    private ReportMessageService reportMessageService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private ContainerService containerService;

    @Autowired
    private GroupService groupService;


    @Operation(summary = "保存设备信息")
    @PostMapping(value = "/setConfig", produces = MediaType.APPLICATION_JSON_VALUE)
    public Result<Object> setConfig(@RequestBody CameraConfigParam param){

        SystemConfig systemConfig = systemConfigService.getSystemConfig();

        CameraConfig cameraConfig;

        if(param.getGroupId()==null){
            List<Group> groupList = groupService.list();
            if(groupList.size()>0) {
                Group group = groupList.get(0);
                param.setGroupId(group.getId());
            }
        }

        if(param.getId() != null){
            cameraConfig = cameraConfigService.getById(param.getId());
            //设置基础信息
            cameraConfig.setCameraDeviceName(param.getCameraDeviceName());
            cameraConfig.setCameraIp(param.getCameraIp());
            cameraConfig.setCameraPort(param.getCameraPort());
            cameraConfig.setCameraRtspPort(param.getCameraRtspPort());
            cameraConfig.setOnvifUser(param.getOnvifUser());
            cameraConfig.setOnvifPasswd(param.getOnvifPasswd());
            cameraConfig.setCameraLongitude(param.getCameraLongitude());
            cameraConfig.setCameraLatitude(param.getCameraLatitude());
            cameraConfig.setCameraAltitude(param.getCameraAltitude());
            cameraConfig.setPanAngle(param.getPanAngle());
            cameraConfig.setTiltAngle(param.getTiltAngle());
            cameraConfig.setCameraFocalLenMax(param.getCameraFocalLenMax());
            cameraConfig.setCameraFocalLenMin(param.getCameraFocalLenMin());
            cameraConfig.setCameraZoomRangeMax(param.getCameraZoomRangeMax());
            cameraConfig.setCameraTiltRangeMax(param.getCameraTiltRangeMax());
            cameraConfig.setCameraTiltRangeMin(param.getCameraTiltRangeMin());

            cameraConfig.setPushStream(param.getPushStream());
            cameraConfig.setAiPushStream(param.getAiPushStream());
            cameraConfig.setPullStream(param.getPullStream());
            cameraConfig.setAiPullStream(param.getAiPullStream());

            cameraConfig.setAutoZoom(param.getAutoZoom());
            cameraConfig.setPixelSize(param.getPixelSize());
            cameraConfig.setDeviceType(param.getDeviceType());
            cameraConfig.setReverse(param.getReverse());
            cameraConfig.setSmart(param.getSmart());
            cameraConfig.setGroupId(param.getGroupId());
            cameraConfig.setDetectMaxDist(param.getDetectMaxDist());
            cameraConfig.setDetectMinDist(param.getDetectMinDist());
            cameraConfig.setHorizontalFov(param.getHorizontalFov());
            cameraConfig.setVerticalFov(param.getVerticalFov());
            cameraConfig.setPtdPort(param.getPtdPort());

            //下发修改光电设备参数消息
            try {
                reportMessageService.adjustDeviceInfo(cameraConfig, systemConfig);
            } catch (Exception e) {
                log.error("MQTT下发修改光电设备参数事件异常，deviceId:{}",cameraConfig.getCameraDeviceId());
            }

        }else{
            cameraConfig = new CameraConfig();
            //生成设备id
            String deviceId = GeneratorUtil.generateDeviceId(systemConfig.getEdgeId());
            String dispatcherTopicName = CacheConstants.DISPATCHER_TOPIC_PREFIX+deviceId;
            cameraConfig.setCameraDeviceId(deviceId);
            cameraConfig.setDispatcherTopic(dispatcherTopicName);
            //设置基础信息
            cameraConfig.setCameraDeviceName(param.getCameraDeviceName());
            cameraConfig.setCameraIp(param.getCameraIp());
            cameraConfig.setCameraPort(param.getCameraPort());
            cameraConfig.setCameraRtspPort(param.getCameraRtspPort());
            cameraConfig.setOnvifUser(param.getOnvifUser());
            cameraConfig.setOnvifPasswd(param.getOnvifPasswd());
            cameraConfig.setCameraLongitude(param.getCameraLongitude());
            cameraConfig.setCameraLatitude(param.getCameraLatitude());
            cameraConfig.setCameraAltitude(param.getCameraAltitude());
            cameraConfig.setPanAngle(param.getPanAngle());
            cameraConfig.setTiltAngle(param.getTiltAngle());
            cameraConfig.setCameraFocalLenMax(param.getCameraFocalLenMax());
            cameraConfig.setCameraFocalLenMin(param.getCameraFocalLenMin());
            cameraConfig.setCameraZoomRangeMax(param.getCameraZoomRangeMax());
            cameraConfig.setCameraTiltRangeMax(param.getCameraTiltRangeMax());
            cameraConfig.setCameraTiltRangeMin(param.getCameraTiltRangeMin());
            cameraConfig.setAutoZoom(param.getAutoZoom());
            cameraConfig.setPixelSize(param.getPixelSize());
            cameraConfig.setDeviceType(param.getDeviceType());
            cameraConfig.setReverse(param.getReverse());
            cameraConfig.setSmart(param.getSmart());
            cameraConfig.setGroupId(param.getGroupId());
            cameraConfig.setDetectMaxDist(param.getDetectMaxDist());
            cameraConfig.setDetectMinDist(param.getDetectMinDist());
            cameraConfig.setHorizontalFov(param.getHorizontalFov());
            cameraConfig.setVerticalFov(param.getVerticalFov());
            cameraConfig.setPullStream(param.getPullStream());
            cameraConfig.setAiPullStream(param.getAiPullStream());
            cameraConfig.setPushStream(param.getPushStream());
            cameraConfig.setAiPushStream(param.getAiPushStream());
            cameraConfig.setPtdPort(param.getPtdPort());


            //通过onvif获取厂商、序列号等信息
            try {
                OnvifDeviceInfo onvifDeviceInfo = onvifService.getDeviceInformation(cameraConfig.getCameraIp(), NumberUtil.parseInt(cameraConfig.getCameraPort()), cameraConfig.getOnvifUser(), cameraConfig.getOnvifPasswd());
                cameraConfig.setManufacturer(onvifDeviceInfo.getManufacturer());
                cameraConfig.setModel(onvifDeviceInfo.getModel());
                cameraConfig.setFirmwareVersion(onvifDeviceInfo.getFirmwareVersion());
                cameraConfig.setSerialNumber(onvifDeviceInfo.getSerialNumber());
            } catch (SOAPException | ConnectException e) {
                log.error("onvif连接出错，deviceId:{}",cameraConfig.getCameraDeviceId(),e);
            }
        }

        //校验控制模式
        if(!cameraConfig.getSmart()){
            if (param.getControlMode() == null) {
                return Result.failed("控制模式未设置");
            }
            ControlMode controlMode = ControlMode.valueOf(param.getControlMode());
            if (controlMode == null) {
                return Result.failed("控制模式设置错误");
            }
            cameraConfig.setControlMode(controlMode);
        }

        //入库
        cameraConfigService.saveOrUpdate(cameraConfig);

        //启动推流任务
        if(cameraConfig.getPubStreamEnabled()){
            List<Container> streamContainerList = containerService.findByCameraIdAndTaskType(cameraConfig.getId(), TaskType.PUB_STREAM);
            if(streamContainerList.isEmpty()) {
                try {
                    taskService.startPubStreamTask(systemConfig, cameraConfig);
                }catch (Exception e){
                    log.error("启动推流任务发生异常, deviceId:{}",cameraConfig.getCameraDeviceId(),e);
                }
            }
        }else{
            //停止推流任务
            try {
                taskService.removePubStreamTask(cameraConfig);
            }catch (Exception e){
                log.error("停止推流任务发生异常, deviceId:{}",cameraConfig.getCameraDeviceId(),e);
            }
        }


        if(!cameraConfig.getSmart()){
            //启动追踪任务
            if(cameraConfig.getAutoStart()) {
                try {
                    taskService.startTrackTask(systemConfig, cameraConfig);
                }catch (Exception e){
                    log.error("启动追踪任务发生异常,deviceId:{}", cameraConfig.getCameraDeviceId(), e);
                }
            }
            try {
                taskService.removeAiPubStreamTask(cameraConfig);
            }catch (Exception e){
                log.error("停止AI推流任务发生异常,deviceId:{}", cameraConfig.getCameraDeviceId(), e);
            }
        }else{
            try {
                taskService.removeTrackTask(cameraConfig);
            }catch (Exception e){
                log.error("停止追踪任务发生异常,deviceId:{}",cameraConfig.getCameraDeviceId(),e);
            }
            try {
                taskService.startAiPubStreamTask(systemConfig, cameraConfig);
            }catch (Exception e){
                log.error("启动AI推流任务发生异常,deviceId:{}", cameraConfig.getCameraDeviceId(), e);
            }
        }


        try {
            reportMessageService.reportDeviceInfo(cameraConfig, systemConfig);
        } catch (Exception e) {
            log.error("MQTT上报设备信息异常，deviceId:{}",cameraConfig.getCameraDeviceId());
        }

        return Result.success();
    }


    @Operation(summary = "获取设备信息（废弃）", hidden = true)
    @GetMapping(value = "/getConfig", produces = MediaType.APPLICATION_JSON_VALUE)
    public Result<CameraConfigVO2> getConfig(String deviceId){
        SystemConfig systemConfig = systemConfigService.getSystemConfig();
        //查询设备
        LambdaQueryWrapper<CameraConfig> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(CameraConfig::getCameraDeviceId, deviceId);
        CameraConfig camera = cameraConfigService.getOne(wrapper);
        return Result.success(new CameraConfigVO2(camera,systemConfig));
    }

    /**
     * 列表
     */
    @Operation(summary = "设备列表")
    @PostMapping(value = "/list", produces = MediaType.APPLICATION_JSON_VALUE)
    public Result<Map<String, Object>> list(@RequestBody CameraConfigListParam cameraConfigListParam){

        List<Group> groups = groupService.list();

        Map<Integer, Group> groupMap = groups.stream().collect(Collectors.toMap(Group::getId, g -> g));

        LambdaQueryWrapper<CameraConfig> wrapper = new LambdaQueryWrapper<>();
        if(StringUtils.isNotBlank(cameraConfigListParam.getContent())){
            wrapper.and(w -> w.like(CameraConfig::getCameraDeviceId, cameraConfigListParam.getContent())
                    .or().like(CameraConfig::getCameraIp, cameraConfigListParam.getContent()));
        }
        if(cameraConfigListParam.getGroupId() != null){
            wrapper.eq(CameraConfig::getGroupId, cameraConfigListParam.getGroupId());
        }
        IPage<CameraConfig> iPage = cameraConfigService.page(new Page<>(cameraConfigListParam.getPage(), cameraConfigListParam.getLimit()), wrapper);
        List<CameraConfigVo> vos = new ArrayList<>();
        Group group;
        for (CameraConfig cameraConfig: iPage.getRecords()) {
            CameraConfigVo cameraConfigVo = new CameraConfigVo(cameraConfig);
            //查询容器状态
            boolean running = taskService.isTrackRunning(cameraConfig);
            boolean pubTaskRunning = taskService.isPubStreamRunning(cameraConfig);
            cameraConfigVo.setRunning(running);
            cameraConfigVo.setPubTaskRunning(pubTaskRunning);
            vos.add(cameraConfigVo);

            //设置组名称
            group = groupMap.get(cameraConfigVo.getGroupId());
            cameraConfigVo.setGroupName(group != null ? group.getName() : null);

        }
        Map<String, Object> data = new HashMap<>(2);
        data.put("records", vos);
        data.put("total", iPage.getTotal());
        return Result.success(data);
    }

    @Operation(summary = "删除设备")
    @GetMapping(value = "/del", produces = MediaType.APPLICATION_JSON_VALUE)
    public Result<Object> del(Integer id){
        CameraConfig cameraConfig = cameraConfigService.getById(id);
        if(cameraConfig!=null){
            taskService.removePubStreamTask(cameraConfig);
            taskService.removeTrackTask(cameraConfig);
        }
        cameraConfigService.removeById(id);
        return Result.success();
    }

    @Operation(summary = "开启/关闭转推")
    @PostMapping(value = "/pubStream", produces = MediaType.APPLICATION_JSON_VALUE)
    public Result<Object> pubStream(@RequestBody PubStreamParam param){
        LambdaUpdateWrapper<CameraConfig> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(CameraConfig::getPubStreamEnabled, param.getPubStreamEnabled()).eq(CameraConfig::getId, param.getId());
        cameraConfigService.update(wrapper);
        CameraConfig cameraConfig = cameraConfigService.getById(Long.parseLong(param.getId()));
        if(param.getPubStreamEnabled()){
            //启动转推
            SystemConfig systemConfig = systemConfigService.getSystemConfig();
            taskService.startPubStreamTask(systemConfig,cameraConfig);
        }else{
            //结束转推
            taskService.removePubStreamTask(cameraConfig);
        }
        return Result.success();
    }


    @Operation(summary = "启动追踪任务")
    @GetMapping(value = "/start", produces = MediaType.APPLICATION_JSON_VALUE)
    public Result<Object> start(String deviceId){
        //查询系统配置
        SystemConfig config = systemConfigService.getSystemConfig();
        //查询设备
        CameraConfig camera = cameraConfigService.findByDeviceId(deviceId);
        try {
            camera.setAutoStart(true);
            cameraConfigService.updateById(camera);
            //启动容器
            taskService.startTrackTask(config,camera);
            return Result.success();
        } catch (Exception e) {
            log.error("启动追踪任务发生异常,设备ID:{}",deviceId,e);
            return Result.failed("容器启动失败");
        }
    }


    @Operation(summary = "停止追踪任务")
    @GetMapping(value = "/stop", produces = MediaType.APPLICATION_JSON_VALUE)
    public Result<Object> stop(String deviceId){
        //查询设备
        CameraConfig camera = cameraConfigService.findByDeviceId(deviceId);
        //删除容器
        try {
            camera.setAutoStart(false);
            cameraConfigService.updateById(camera);
            taskService.removeTrackTask(camera);
            return Result.success();
        } catch (Exception e) {
            log.error("删除容器发生异常,设备ID:{}", deviceId, e);
            return Result.failed("容器停止失败");
        }

    }

    @Operation(summary = "启动转推任务")
    @GetMapping(value = "/startStream", produces = MediaType.APPLICATION_JSON_VALUE)
    public Result<Object> startStream(String deviceId){
        //查询系统配置
        SystemConfig config = systemConfigService.getSystemConfig();
        //查询设备
        CameraConfig camera = cameraConfigService.findByDeviceId(deviceId);
        try {
            //启动容器
            taskService.startPubStreamTask(config,camera);
            return Result.success();
        } catch (Exception e) {
            log.error("启动追踪任务发生异常,设备ID:{}",deviceId,e);
            return Result.failed("容器启动失败");
        }
    }


    @Operation(summary = "停止转推任务")
    @GetMapping(value = "/stopStream", produces = MediaType.APPLICATION_JSON_VALUE)
    public Result<Object> stopStream(String deviceId){
        //查询设备
        CameraConfig camera = cameraConfigService.findByDeviceId(deviceId);
        //删除容器
        try {
            taskService.removePubStreamTask(camera);
            return Result.success();
        } catch (Exception e) {
            log.error("删除容器发生异常,设备ID:{}", deviceId, e);
            return Result.failed("容器停止失败");
        }

    }

    @Operation(summary = "获取拉流地址")
    @PostMapping(value = "/getRtspStream", produces = MediaType.APPLICATION_JSON_VALUE)
    public Result<Object> getRtspStream(@RequestBody OnvifParam onvifParam){
        try {
            List<CameraRtspInfo> cameraRtspInfoList = onvifService.getRtspStreamList(onvifParam.getIp(),onvifParam.getPort(),onvifParam.getUsername(),onvifParam.getPassword());
            return Result.success(cameraRtspInfoList);
        } catch (Exception e) {
            log.error("获取拉流地址发生异常",e);
            return Result.failed("获取拉流地址发生异常");
        }
    }

    @Operation(summary = "获取控制模式")
    @GetMapping(value = "/getControlModeList", produces = MediaType.APPLICATION_JSON_VALUE)
    public Result<Object> getControlModeList() {
        return Result.success(Arrays.stream(ControlMode.values()).map(ControlModeDto::valueOf).collect(Collectors.toList()));
    }

}
